﻿using CMS.Utils;
using Microsoft.IdentityModel;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using CMS.Excep;

namespace CMS.Auth
{
    public class UserTokenManager
    {
        string aud = "http://dse.com";
        string iss = "http://dse.com";
        SymmetricSecurityKey key;
        SigningCredentials credentials;
        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
        TokenValidationParameters tokenValidationParameters;

        public SymmetricSecurityKey GetSymmetricSecurityKey()
        {
            if (key == null)
            {
                key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SECRETKEY));
            }
            return key;
        }
        public SigningCredentials GetCredentials()
        {
            if (credentials == null)
            {
                credentials = new SigningCredentials(GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256Signature);
            }
            return credentials;
        }
        public TokenValidationParameters GetTokenValidationParameters()
        {
            if (tokenValidationParameters == null)
            {
                tokenValidationParameters = new TokenValidationParameters()
                {
                    IssuerSigningKey = GetSymmetricSecurityKey(),
                    ValidAudience = aud,
                    ValidIssuer = iss,
                    ValidateLifetime = false,

                };
            }
            return tokenValidationParameters;
        }

        public string MakeToken(string userid,string name,string isAdm)
        {
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim("id", userid),
                    new Claim("name", name),
                    new Claim("nonce", Guid.NewGuid().ToString().Replace("-","")),
                    new Claim("aud", aud),
                    new Claim("isAdm", isAdm),
                    new Claim("iss", iss)
                }),
                SigningCredentials = GetCredentials(),
                Expires = DateTime.UtcNow.AddYears(1)
            };
            try
            {
                var tokenStr = tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor));
                return tokenStr;
            }
            catch (Exception ex)
            {
                Logger.Err(MyUtils.FormatExceptionInfo(ex));
                throw new MyAuthorizationException("创建授权TOKEN失败");
            }
        }

        public  void SetupUserFromToken(OptUser user, string tokenStr)
        {
            var jwtToken = RestoreToken(tokenStr);
            var userid = jwtToken.Payload["id"].ToString()!;
            user.UserName = jwtToken.Payload["name"].ToString()!;
            user.IsAdm = jwtToken.Payload["isAdm"].ToString() == "Y";
            user.UserId = userid;
            user.Token = tokenStr;
        }
        public  void SetupUser(OptUser user)
        {
            var httpContext = ServiceLoader.GetHttpContext();
            StringValues tokenStrVal;
            var msgInHeader = httpContext.Request.Headers.TryGetValue("Authorization", out tokenStrVal);
            if (!msgInHeader)
                httpContext.Request.Query.TryGetValue("Authorization", out tokenStrVal);
            var tokenStr = tokenStrVal.ToString();
            var prefix = "bearer";
            if (tokenStr.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            {
                tokenStr = tokenStr.Remove(0, prefix.Length).Trim();
            }
            SetupUserFromToken(user, tokenStr);
        }
        public  JwtSecurityToken RestoreToken(string tokenStr)
        {
            SecurityToken securityToken;
            try
            {
                var principal = tokenHandler.ValidateToken(tokenStr, GetTokenValidationParameters(), out securityToken);
                JwtSecurityToken jwtSecurityToken = (JwtSecurityToken)securityToken;
                return jwtSecurityToken;
            }
            catch (Exception ex)
            {
                throw new MyAuthorizationException("TOKEN验证失败", ex);
            }
        }

    }
}
